package server

import (
  "bytes"
  "io"
  "time"
)

type responseWriter interface {
  writeError(error)
  writeStatus(string)
  writeInteger(int64)
  writeBulk([]byte)
  writeArray([]interface{})
  writeSliceArray([][]byte)
  writeBulkFrom(int64, io.Reader)
  flush()
}

type requestContext struct {
  app *App

  remoteAddr string
  cmd        string
  args       [][]byte

  resp responseWriter

  syncBuf bytes.Buffer

  reqErr chan error

  buf bytes.Buffer
}

func newRequestContext(app *App) *requestContext {
  req := new(requestContext)

  req.app = app

  req.reqErr = make(chan error)

  return req
}

func (req *requestContext) perform() {
  var err error

  start := time.Now()

  if len(req.cmd) == 0 {
    err = ErrEmptyCommand
  } else if exeCmd, ok := regCmds[req.cmd]; !ok {
    err = ErrNotFound
  } else {
    go func() {
      req.reqErr <- exeCmd(req)
    }()

    err = <-req.reqErr
  }

  duration := time.Since(start)

  if req.app.access != nil {
    fullCmd := req.catGenericCommand()
    cost := duration.Nanoseconds() / 1000000

    truncateLen := len(fullCmd)
    if truncateLen > 256 {
      truncateLen = 256
    }

    req.app.access.Log(req.remoteAddr, cost, fullCmd[:truncateLen], err)
  }

  if err != nil {
    req.resp.writeError(err)
  }
  req.resp.flush()
  return
}

// func (h *requestHandler) catFullCommand(req *requestContext) []byte {
//
// 	// if strings.HasSuffix(cmd, "expire") {
// 	// 	catExpireCommand(c, buffer)
// 	// } else {
// 	// 	catGenericCommand(c, buffer)
// 	// }
//
// 	return h.catGenericCommand(req)
// }

func (req *requestContext) catGenericCommand() []byte {
  buffer := req.buf
  buffer.Reset()

  buffer.Write([]byte(req.cmd))

  for _, arg := range req.args {
    buffer.WriteByte(' ')
    buffer.Write(arg)
  }

  return buffer.Bytes()
}
